#pragma once

#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "RoomLightManagerSubsystem.generated.h"

class URoomManagerSubsystem;

USTRUCT(BlueprintType)
struct FRoomLightInfo
{
	GENERATED_BODY()

	UPROPERTY(Transient)
	FName RoomName = NAME_None;

	UPROPERTY(Transient)
	TSet<TObjectPtr<AActor>> RoomSwitches;

	UPROPERTY(Transient)
	TSet<TObjectPtr<AActor>> RoomLights;
};

/**
 * 
 */
UCLASS(ClassGroup =(RoomLight))
class PHOBIA_API URoomLightManagerSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()

protected:
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;
	virtual void Deinitialize() override;

public:
	UFUNCTION(BlueprintCallable)
	TArray<UActorComponent*> GetRoomComponentsByClass(const FName& RoomName, TSubclassOf<UActorComponent> ComponentClass);

	template <typename ComponentType>
	TArray<ComponentType*> GetRoomComponents(const FName& RoomName);

	// TODO 后期可能走统一事件
	UFUNCTION(BlueprintCallable)
	void StartGame();
	// TODO 后期可能走统一事件
	UFUNCTION(BlueprintCallable)
	void FinishGame();

	// 电闸调用，注册电闸
	void RegisterElectricSwitch(AActor* InElectricSwitch);
	void UnregisterElectricSwitch(AActor* InElectricSwitch);

	// 开关调用，注册开关
	void RegisterRoomSwitch(AActor* InRoomSwitch);
	void UnregisterRoomSwitch(AActor* InRoomSwitch);

	// 灯光调用，注册灯光
	void RegisterRoomLight(AActor* InRoomLight);
	void UnregisterRoomLight(AActor* InRoomLight);

protected:
	// 游戏开始时收集信息
	void CollectLightInfos(const URoomManagerSubsystem* RoomManagerSubsystem);
	void EnsureLightInfos();

private:
	UPROPERTY(Transient)
	TObjectPtr<AActor> ElectricSwitch;

	UPROPERTY(Transient)
	TSet<TObjectPtr<AActor>> RoomSwitches;

	UPROPERTY(Transient)
	TSet<TObjectPtr<AActor>> RoomLights;

	UPROPERTY(Transient)
	TMap<FName, FRoomLightInfo> RoomLightInfoMap;
};

template <typename ComponentType>
TArray<ComponentType*> URoomLightManagerSubsystem::GetRoomComponents(const FName& RoomName)
{
	TArray<ComponentType*> Components;
	if (!RoomLightInfoMap.Contains(RoomName))
	{
		UE_LOG(LogTemp, Error, TEXT("RoomName [%s] not found."), *RoomName.ToString());
		return Components;
	}

	FRoomLightInfo& LightInfo = RoomLightInfoMap[RoomName];
	for (TObjectPtr<AActor> RoomLight : LightInfo.RoomLights)
	{
		TArray<ComponentType*> FoundComponents;
		RoomLight->GetComponents(FoundComponents);
		Components.Append(FoundComponents);
	}
	return Components;
}
